package value

import (
	"context"
	"regexp"
	"strconv"
)

type String string

func (String) NixType() string {
	return "string"
}

func (s String) String() string {
	return strconv.Quote(string(s))
}

func (String) Strict(context.Context) error {
	return nil
}

// Identifier returns the string escaped in an appropriate way for being used as
// a Nix identifier. Strings that can not be parsed as identifiers by Nix are
// quoted.
func (s String) Identifier() string {
	if s.isValidIdentifier() {
		return string(s)
	} else {
		return s.String()
	}
}

// isKeyword checks whether the string lexically matches the
// "identifier" production, but is not parsed as an identifier. See
// also cppnix commit b72bc4a972fe568744d98b89d63adcd504cb586c.
func (s String) isKeyword() bool {
	return s == "if" || s == "then" || s == "else" ||
		s == "assert" || s == "with" || s == "let" ||
		s == "in" || s == "rec" || s == "inherit"
}

var identifierRegexp = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_'-]*$`)

// isValidIdentifier checks whether the string can be used as an
// unquoted identifier in Nix.
func (s String) isValidIdentifier() bool {
	return identifierRegexp.MatchString(string(s)) && !s.isKeyword()
}
